﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Diagnostics;

namespace DimensionData.Data2
{
    public class DTree
    {
        public int Level { get; set; }
        public List<DTreeNode> Nodes { get; set; }
        public DCTable Table { get; set; }

        /// <summary>
        /// 平面化之后的数据行
        /// </summary>
        private List<DRow> _rows;

        public DTree()
        {
            Nodes = new List<DTreeNode>();
        }

        public void Relate(DTree tree)
        {
        }

        /// <summary>
        /// 平面化
        /// </summary>
        /// <returns></returns>
        public DataTable Complanate()
        {
            DataTable table = new DataTable();
            DTreeNode[] lineNodes = new DTreeNode[Table.RelationChain.Relations.Count + 1];
            for (int index = 0; index < lineNodes.Length; index++)
            {
                table.Columns.Add(string.Format("Level{0}", index));
                table.Columns.Add(string.Format("Code{0}", index));
                table.Columns.Add(string.Format("Name{0}", index));
            }
            
            Stack<DTreeNode> stack = new Stack<DTreeNode>();
            for (int index = Nodes.Count - 1; index >= 0; index--)
            {
                stack.Push(Nodes[index]);
            }

            while (stack.Count > 0)
            {
                DTreeNode node = stack.Pop();
                lineNodes[node.Tree.Level] = node;

                if (node.NextTree != null)
                {
                    for (int index = node.NextTree.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.NextTree.Nodes[index]);
                    }
                }
                else
                {
                    string destLevelField = string.Format("Level{0}", node.Tree.Level);
                    string destCodeField = string.Format("Code{0}", node.Tree.Level);
                    string destNameField = string.Format("Name{0}", node.Tree.Level);
                    DataRow newRow = table.NewRow();
                    newRow[destLevelField] = node.Level;
                    newRow[destCodeField] = node.Code;
                    newRow[destNameField] = node.Name;
                    for (int treeIndex = node.Tree.Level - 1; treeIndex >= 0; treeIndex--)
                    {
                        string prevDestLevelField = string.Format("Level{0}", treeIndex);
                        string prevDestCodeField = string.Format("Code{0}", treeIndex);
                        string prevDestNameField = string.Format("Name{0}", treeIndex);
                        newRow[prevDestLevelField] = lineNodes[treeIndex].Level;
                        newRow[prevDestCodeField] = lineNodes[treeIndex].Code;
                        newRow[prevDestNameField] = lineNodes[treeIndex].Name;
                    }
                    table.Rows.Add(newRow);

                    for (int index = node.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.Nodes[index]);
                    }
                }
            }


            return table;
        }

        public List<DRow> Complanate2()
        {
            if (_rows == null)
            {
                List<DRow> rows = new List<DRow>();

                int dCount = Table.RelationChain.Relations.Count + 1;
                DTreeNode[] lineNodes = new DTreeNode[dCount];

                Stack<DTreeNode> stack = new Stack<DTreeNode>();
                for (int index = Nodes.Count - 1; index >= 0; index--)
                {
                    //PushRoot(stack, Nodes[index]);
                    stack.Push(Nodes[index]);
                }

                while (stack.Count > 0)
                {
                    DTreeNode node = stack.Pop();
                    lineNodes[node.Tree.Level] = node;
                    Debug.WriteLine(string.Format("update lineNodes level:{0} name:{1}", node.Tree.Level, node.Name));

                    if (node.NextTree != null)
                    {
                        for (int index = node.Nodes.Count - 1; index >= 0; index--)
                        {
                            stack.Push(node.Nodes[index]);
                        }

                        for (int index = node.NextTree.Nodes.Count - 1; index >= 0; index--)
                        {
                            stack.Push(node.NextTree.Nodes[index]);
                        }
                    }
                    else
                    {
                        DRow row = new DRow();
                        row.RowIndex = rows.Count;
                        rows.Add(row);

                        row.Items = new DItem[dCount];
                        row.Items[node.Tree.Level] = new DItem();
                        row.Items[node.Tree.Level].Level = node.Level;
                        row.Items[node.Tree.Level].Code = node.Code;
                        row.Items[node.Tree.Level].Name = node.Name;
                        row.Items[node.Tree.Level].Formula = node.Formula;
                        for (int treeIndex = node.Tree.Level - 1; treeIndex >= 0; treeIndex--)
                        {
                            row.Items[treeIndex] = new DItem();
                            row.Items[treeIndex].Level = lineNodes[treeIndex].Level;
                            row.Items[treeIndex].Code = lineNodes[treeIndex].Code;
                            row.Items[treeIndex].Name = lineNodes[treeIndex].Name;
                            row.Items[treeIndex].Formula = lineNodes[treeIndex].Formula;
                        }

                        for (int index = node.Nodes.Count - 1; index >= 0; index--)
                        {
                            stack.Push(node.Nodes[index]);
                        }
                    }
                }

                _rows = rows;
                return rows;
            }
            return _rows;
        }

        private void PushRoot(Stack<DTreeNode> stack, DTreeNode root)
        {
            for (int index = root.Nodes.Count - 1; index >= 0; index--)
            {
                stack.Push(root.Nodes[index]);
                PushRoot(stack, root.Nodes[index]);
            }
        }
    }
}
